<?php
class verify
{
	private static array $rules = [];
	private array $alias = [];
	private array $msgs = [];
	private array $err  = [];

	public function __construct()
	{
		if (count(self::$rules) === 0) {
			$this->setDefaultRules();
		}
	}

	/**
	 * @param string $key
	 * @param array  $call
	 * @return $this
	 */
	public function addRule(string $key, array $call)
	{
		self::$rules[$key] = $call;
		return $this;
	}

	/**
	 * @param array $msgs
	 * @return $this
	 */
	public function setMessages(array $msgs)
	{
		$this->msgs = $msgs + $this->msgs;
		return $this;
	}

	private function runRule($value, $rules, $name, $isGB = false)
	{
		$arr = explode('|', $rules);
		foreach ($arr as $val) {
			$ar = explode(':', $val);
			if (count($ar) > 1) {
				$args = explode(',', $ar[1]);
			} else {
				$args = [];
			}
			$msg = $this->msgs[$ar[0]] ?? self::$rules[$ar[0]]['msg'];
			$msg = str_replace(':attribute', $name, $msg);
			foreach ($args as $i => $g) {
				// 含有中文
				if ($isGB === true) {
					$msg = str_replace([':arg' . ($i + 1), '位'], [$g / 3, '个汉字'], $msg);
				} else {
					$msg = str_replace(':arg' . ($i + 1), $g, $msg);
				}
			}
			array_unshift($args, $value);
			if ($this->checkOne(self::$rules[$ar[0]]['fn'], $args, $msg) === false) {
				break;
			}
		}
	}

	/**
	 * @param       $arr
	 * @param array $rules
	 * @param array $msgs
	 * @return $this
	 */
	public function validate(array $arr, array $rules, $msgs = [])
	{
		$this->msgs = $msgs + $this->msgs;
		foreach ($rules as $k => $r) {
			if (isset($arr[$k])) {
				if (is_array($arr[$k])) {
					$arr[$k] = json_encode($arr[$k], 320);
				}
				// 判断是否为中文 暂时不支持判断数组
				$isGB = preg_match('/[\x{4e00}-\x{9fa5}]/u', (string)$arr[$k]) > 0;
				$this->runRule((string)$arr[$k], $r, isset($this->alias[$k]) ? $this->alias[$k] : $k, $isGB);
			} elseif (!str_contains($r, 'required')) {
			} else {
				$this->runRule(null, $r, isset($this->alias[$k]) ? $this->alias[$k] : $k);
			}
		}
		return $this;
	}

	private function checkOne(Closure $call, array $args, $msg)
	{
		if ($call->call($this, ...$args) === false) {
			$this->err[] = $msg;
			return false;
		} else {
			return true;
		}
	}

	/**
	 * @return array
	 */
	public function getErrs()
	{
		return $this->err;
	}

	/**
	 * @return bool
	 */
	public function isOk(): bool
	{
		return count($this->err) === 0;
	}

	/**
	 * @param array $arr
	 * @return $this
	 */
	public function setAliases(array $arr)
	{
		$this->alias = $arr + $this->alias;
		return $this;
	}

	private function setDefaultRules()
	{
		self::$rules = [
			'required' => [
				'msg' => ':attribute不能为空',
				'fn'  => function ($value) {
					if ($value === '' || is_null($value) || (is_array($value) && count($value) < 1)) {
						return false;
					} else {
						return true;
					}
				},
			],
			'numeric'  => [
				'msg' => ':attribute必须是数字',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return is_numeric($value);
				},
			],
			'tel'      => [
				'msg' => ':attribute格式错误',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					if (checkTel == 'checkTel') {
						$checkTel = '/^0?(1[3-9])[0-9]{9}$/';
					} else {
						$checkTel = checkTel;
					}
					if (preg_match($checkTel, $value)) {
						return true;
					} else {
						return false;
					}
				},
			],
			'id_card'  => [
				'msg' => ':attribute格式错误',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					$pattern = '/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/';
					if (preg_match($pattern, $value)) {
						return true;
					} else {
						return false;
					}
				},
			],

			'min'          => [
				'msg' => ':attribute不能小于:arg1',
				'fn'  => function ($value, $arg1) {
                    if (empty($value)) {
                        return true;
                    }
					return $value >= $arg1;
				},
			],
			'max'          => [
				'msg' => ':attribute不能大于:arg1',
				'fn'  => function ($value, $arg1) {
                    if (empty($value)) {
                        return true;
                    }
					return $value <= $arg1;
				},
			],
			'min_len'      => [
				'msg' => ':attribute长度不能小于:arg1位',
				'fn'  => function ($value, $arg1) {
                    if (empty($value)) {
                        return true;
                    }
					return strlen($value) >= $arg1;
				},
			],
			'max_len'      => [
				'msg' => ':attribute长度不能大于:arg1位',
				'fn'  => function ($value, $arg1) {
                    if (empty($value)) {
                        return true;
                    }
					return strlen($value) <= $arg1;
				},
			],
			'unsigned_int' => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return is_numeric($value) && !str_contains($value, '.') && floatval($value) > 0.1;
				},
			],
			'email'        => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
				},
			],
			'url'          => [
				'msg' => ':attribute格式不正确，非网址',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return filter_var($value, FILTER_VALIDATE_URL) !== false;
				},
			],
			'ip'           => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return filter_var($value, FILTER_VALIDATE_IP) !== false;
				},
			],
			'ip4'          => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
				},
			],
			'ip6'          => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
				},
			],
			'date'         => [
				'msg' => ':attribute格式不正确',
				'fn'  => function ($value) {
                    if (empty($value)) {
                        return true;
                    }
					return strtotime($value);
				},
			],
		];
	}
}
